﻿/*
#if !defined(_CXXL3D_SSE)
#include <Math\MATH_CPU.HPP>
#else
#endif
*/


#include <Sys\MATH.HPP>
#include <Sys\C3DNODE.HPP>
#include <Sys\MATRIX.HPP>
#include <Sys\CSMART_PTR.HPP>

using namespace CxxlMan;
using namespace Cxxl3D;

// 元件介面的識別碼
#define CC3D_Node_ClassID L"04E582FF-BBA3-483f-BB62-EFF28931B42C"

cxxlObject *New_CC3D_Node(void *p);
cxxlPreserve2 *Regenera_CC3D_Node(const wchar_t *ClassID);


// IC3D_Node 的實作
class CC3D_Node:public IC3D_Node
{
  P2Smart_Set<CC3D_Node> m_Child_Nodes_Set; // 這個節點之下的子節點

  CSmart_Ptr<const Matrix4x4> m_WorldMatrix_cPtr; // 這個節點代表的世界座標轉換矩陣

  // 產生新的子節點，並為它產生和本身相同的 World Matrix
  virtual Smart_Ptr<IC3D_Node> cxxlFASTCALL NewChdNode()
  {
    CriticalSecHandle AutoCSH(csPreserve);
    Smart_Ptr<IC3D_Node> IC3D_Node_Ptr = IC3D_Node::Create(CSmart_Cast<const Matrix4x4>( CloneWorldMatrix() ));
    m_Child_Nodes_Set.Add( Smart_Cast<CC3D_Node>(IC3D_Node_Ptr) );
    return IC3D_Node_Ptr;
  }

  // 檢查是否為子孫節點
  bool cxxlFASTCALL isOffspring(const Smart_Ptr<CC3D_Node> &CC3D_Node_Arg)
  {
    CriticalSecHandle AutoCSH(csPreserve);

    Smart_Ptr<cxxlList<CC3D_Node> > Child_Node_List = m_Child_Nodes_Set.GetList();
    Child_Node_List->ResetPT(toHead);
    unsigned long Count = Child_Node_List->GetCount();
    Smart_Ptr<CC3D_Node> Chd_Node_Ptr = (*Child_Node_List)++;
    for(unsigned long n = 0; n < Count; ++n, Chd_Node_Ptr = (*Child_Node_List)++)
    {
      if((CC3D_Node*)Chd_Node_Ptr == (CC3D_Node*)CC3D_Node_Arg)
        return true;

      if(Chd_Node_Ptr->isOffspring(CC3D_Node_Arg))
        return true;
    }

    return false;      
  }

  // 加入指定的子節點，若會造成循環，拒絕加入並回覆 false
  virtual bool cxxlFASTCALL AttachChdNode(const Smart_Ptr<IC3D_Node> &ChdNode_Arg)
  {    
    CriticalSecHandle AutoCSH(csPreserve);

    Smart_Ptr<CC3D_Node> ChdNode_Ptr = Smart_Cast<CC3D_Node>(ChdNode_Arg);

    if(ChdNode_Ptr->isOffspring(this) == false)
    {
      m_Child_Nodes_Set.Add( ChdNode_Ptr );
      return true;
    }
    else
      return false;    
  }

  // 分離指定的子節點
  virtual void cxxlFASTCALL DetachChdNode(const Smart_Ptr<IC3D_Node> &ChdNode_Arg)
  {
    csPreserve.Enter();
    m_Child_Nodes_Set.Delete( Smart_Cast<CC3D_Node>(ChdNode_Arg) );
    csPreserve.Leave();
  }

  // 複製傳回 World Matrix4x4
  virtual CxxlMan::CSmart_Ptr<Matrix4x4> cxxlFASTCALL CloneWorldMatrix() const  
  {
    CriticalSecHandle AutoCSH(csPreserve);
    return new Matrix4x4(*m_WorldMatrix_cPtr);
  }

  // 傳回 World Matrix4x4
  virtual CxxlMan::CSmart_Ptr<const Matrix4x4> cxxlFASTCALL GetWorldMatrix() const
  {
    CriticalSecHandle AutoCSH(csPreserve);
    return m_WorldMatrix_cPtr;
  }


  // 直接配置 World Matrix4x4
  virtual void cxxlFASTCALL AssignWorldMatrix(const CSmart_Ptr<const Matrix4x4> &Matrix4x4_Arg)
  {
    csPreserve.Enter();

    m_WorldMatrix_cPtr = Matrix4x4_Arg;    

    csPreserve.Leave();
  }


  // 和指定的矩陣做相乘運算 this = this * actMatrix4x4
  void cxxlFASTCALL TransformsXact(const Matrix4x4 &actMatrix4x4)
  {
    csPreserve.Enter();

    m_WorldMatrix_cPtr = new Matrix4x4(*(const Matrix4x4*)m_WorldMatrix_cPtr * actMatrix4x4);

    Smart_Ptr<cxxlList<CC3D_Node> > Child_Node_List = m_Child_Nodes_Set.GetList();

    csPreserve.Leave();

    Child_Node_List->ResetPT(toHead);
    unsigned long Count = Child_Node_List->GetCount();
    Smart_Ptr<CC3D_Node> CC3D_Node_Ptr = (*Child_Node_List)++;
    for(unsigned long n = 0; n < Count; ++n, CC3D_Node_Ptr = (*Child_Node_List)++)
      CC3D_Node_Ptr->TransformsXact(actMatrix4x4);
  }

  // 位移，以世界座標為參考座標
  virtual void cxxlFASTCALL Translate_W(C3D_FLOAT x, C3D_FLOAT y, C3D_FLOAT z)
  {
    csPreserve.Enter();

    Matrix4x4 *mp = new Matrix4x4(*m_WorldMatrix_cPtr);
    C3DVector4 &v = (*mp)[3];    
    
    v.x = v.x + x;
    v.y = v.y + y;
    v.z = v.z + z;

    m_WorldMatrix_cPtr = mp;

    Smart_Ptr<cxxlList<CC3D_Node> > Child_Node_List = m_Child_Nodes_Set.GetList();

    csPreserve.Leave();

    Child_Node_List->ResetPT(toHead);
    unsigned long Count = Child_Node_List->GetCount();
    Smart_Ptr<CC3D_Node> CC3D_Node_Ptr = (*Child_Node_List)++;
    for(unsigned long n = 0; n < Count; ++n, CC3D_Node_Ptr = (*Child_Node_List)++)
      CC3D_Node_Ptr->Translate_W(x,y,z);
  }

  // 位移，以 IC3D_Node 的局部座標為參考座標
  virtual void cxxlFASTCALL Translate_L(C3D_FLOAT x, C3D_FLOAT y, C3D_FLOAT z)
  {

    csPreserve.Enter();

    Matrix4x4 *pMatrix4x4 = new Matrix4x4(*m_WorldMatrix_cPtr);
    C3DMatrix4x4 *pC3DMatrix4x4 = (C3DMatrix4x4 *)pMatrix4x4;

    Matrix4x4 InvertMatrix = CoordinateInvert(*pMatrix4x4);

    pC3DMatrix4x4->m_Vec3 = pC3DMatrix4x4->m_Vec3 + pC3DMatrix4x4->m_Vec0 * x + pC3DMatrix4x4->m_Vec1 * y + pC3DMatrix4x4->m_Vec2 * z;

    Matrix4x4 actMatrix4x4 = InvertMatrix * (*pMatrix4x4);

    m_WorldMatrix_cPtr = pMatrix4x4;

    Smart_Ptr<cxxlList<CC3D_Node> > Child_Node_List = m_Child_Nodes_Set.GetList();

    csPreserve.Leave();

    Child_Node_List->ResetPT(toHead);
    unsigned long Count = Child_Node_List->GetCount();
    Smart_Ptr<CC3D_Node> CC3D_Node_Ptr = (*Child_Node_List)++;
    for(unsigned long n = 0; n < Count; ++n, CC3D_Node_Ptr = (*Child_Node_List)++)
      CC3D_Node_Ptr->TransformsXact(actMatrix4x4);
  }

  // 旋轉，以世界座標為參考座標
  virtual void cxxlFASTCALL Rotate_W(C3D_FLOAT x, C3D_FLOAT y, C3D_FLOAT z, const C3D_FLOAT radian)
  {
    Matrix4x4 rotMatrix4x4; // = Rotate(Vector4(x,y,z,0), radian);

    if(x != 0)
    {
      if( y != 0 || z != 0)
      {
        Vector4 v(x,y,z,0);
        Vector3Normalize(v);
        rotMatrix4x4 = Rotate(v, radian);
      }
      else // x != 0 y == 0 z == 0
        rotMatrix4x4 = (x < 0)? RotateX(-radian):RotateX(radian);
    }
    else if(y != 0)
    {
      if(z != 0)
      {
        Vector4 v(x,y,z,0);
        Vector3Normalize(v);
        rotMatrix4x4 = Rotate(v, radian);
      }
      else // x == 0 y != 0 z == 0
        rotMatrix4x4 = (y < 0)? RotateY(-radian):RotateY(radian);
    }
    else if(z != 0) // x == 0 y == 0 z != 0
      rotMatrix4x4 = (z < 0)? RotateZ(-radian):RotateZ(radian);
    else // x == 0 y == 0 z == 0
      return;

    csPreserve.Enter();

    m_WorldMatrix_cPtr = new Matrix4x4(*(const Matrix4x4*)m_WorldMatrix_cPtr * rotMatrix4x4);

    Smart_Ptr<cxxlList<CC3D_Node> > Child_Node_List = m_Child_Nodes_Set.GetList();

    csPreserve.Leave();

    Child_Node_List->ResetPT(toHead);
    unsigned long Count = Child_Node_List->GetCount();
    Smart_Ptr<CC3D_Node> CC3D_Node_Ptr = (*Child_Node_List)++;
    for(unsigned long n = 0; n < Count; ++n, CC3D_Node_Ptr = (*Child_Node_List)++)
      CC3D_Node_Ptr->TransformsXact(rotMatrix4x4);

  }

  // 旋轉，以 IC3D_Node 的局部座標為參考座標
  virtual void cxxlFASTCALL Rotate_L(C3D_FLOAT x, C3D_FLOAT y, C3D_FLOAT z, const C3D_FLOAT radian)
  {
    Matrix4x4 rotMatrix4x4; // = Rotate(Vector4(x,y,z,0), radian);

    if(x != 0)
    {
      if( y != 0 || z != 0)
      {
        Vector4 v(x,y,z,0);
        Vector3Normalize(v);
        rotMatrix4x4 = Rotate(v, radian);
      }
      else // x != 0 y == 0 z == 0
        rotMatrix4x4 = (x < 0)? RotateX(-radian):RotateX(radian);
    }
    else if(y != 0)
    {
      if(z != 0)
      {
        Vector4 v(x,y,z,0);
        Vector3Normalize(v);
        rotMatrix4x4 = Rotate(v, radian);
      }
      else // x == 0 y != 0 z == 0
        rotMatrix4x4 = (y < 0)? RotateY(-radian):RotateY(radian);
    }
    else if(z != 0) // x == 0 y == 0 z != 0
      rotMatrix4x4 = (z < 0)? RotateZ(-radian):RotateZ(radian);
    else // x == 0 y == 0 z == 0
      return;

    csPreserve.Enter();
    Matrix4x4 *pMatrix4x4 = new Matrix4x4(*m_WorldMatrix_cPtr);

    Matrix4x4 InvertMatrix = CoordinateInvert(*pMatrix4x4);
    *pMatrix4x4 = rotMatrix4x4 * (*pMatrix4x4);
    Matrix4x4 actMatrix4x4 = InvertMatrix * (*pMatrix4x4);
    m_WorldMatrix_cPtr = pMatrix4x4;

    Smart_Ptr<cxxlList<CC3D_Node> > Child_Node_List = m_Child_Nodes_Set.GetList();

    csPreserve.Leave();

    Child_Node_List->ResetPT(toHead);
    unsigned long Count = Child_Node_List->GetCount();
    Smart_Ptr<CC3D_Node> CC3D_Node_Ptr = (*Child_Node_List)++;
    for(unsigned long n = 0; n < Count; ++n, CC3D_Node_Ptr = (*Child_Node_List)++)
      CC3D_Node_Ptr->TransformsXact(actMatrix4x4);
  }

  // 縮放，以世界座標為參考座標
  virtual void cxxlFASTCALL Scale_W(C3D_FLOAT x, C3D_FLOAT y, C3D_FLOAT z)
  {
    csPreserve.Enter();
    Matrix4x4 ScaleMatrix = Scale(x,y,z);
    m_WorldMatrix_cPtr = new Matrix4x4(*(const Matrix4x4*)m_WorldMatrix_cPtr * ScaleMatrix);

    Smart_Ptr<cxxlList<CC3D_Node> > Child_Node_List = m_Child_Nodes_Set.GetList();

    csPreserve.Leave();

    Child_Node_List->ResetPT(toHead);
    unsigned long Count = Child_Node_List->GetCount();
    Smart_Ptr<CC3D_Node> CC3D_Node_Ptr = (*Child_Node_List)++;
    for(unsigned long n = 0; n < Count; ++n, CC3D_Node_Ptr = (*Child_Node_List)++)
      CC3D_Node_Ptr->TransformsXact(ScaleMatrix);
  }

  // 縮放，以 IC3D_Node 的局部座標為參考座標
  virtual void cxxlFASTCALL Scale_L(C3D_FLOAT x, C3D_FLOAT y, C3D_FLOAT z)
  {
    csPreserve.Enter();
    Matrix4x4 *pMatrix4x4 = new Matrix4x4(*m_WorldMatrix_cPtr);

    Matrix4x4 InvertMatrix = CoordinateInvert(*pMatrix4x4);
    Matrix4x4 ScaleMatrix = Scale(x,y,z);

    *pMatrix4x4 = ScaleMatrix * (*pMatrix4x4);
    Matrix4x4 actMatrix4x4 = InvertMatrix * (*pMatrix4x4);
    m_WorldMatrix_cPtr = pMatrix4x4;

    Smart_Ptr<cxxlList<CC3D_Node> > Child_Node_List = m_Child_Nodes_Set.GetList();

    csPreserve.Leave();

    Child_Node_List->ResetPT(toHead);
    unsigned long Count = Child_Node_List->GetCount();
    Smart_Ptr<CC3D_Node> CC3D_Node_Ptr = (*Child_Node_List)++;
    for(unsigned long n = 0; n < Count; ++n, CC3D_Node_Ptr = (*Child_Node_List)++)
      CC3D_Node_Ptr->TransformsXact(actMatrix4x4);
  }


protected:

  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F)
  {
    if(F != NULL && IC3D_Node::Ref(F))
    {
//      ((Matrix4x4*)m_WorldMatrix_cPtr)->Lock();
      
      bool r = F->Ref((C3D_FLOAT*)(const Matrix4x4*)m_WorldMatrix_cPtr, 16, L"CC3D_Node.WorldMatrix");

//      ((Matrix4x4*)m_WorldMatrix_cPtr)->UnLock();

      return r;
    }
    else
      return false;
  }


public:

  // Constructor
  CC3D_Node(const CSmart_Ptr<const Matrix4x4> &Matrix4x4_Arg)
    :cxxlObject(CxxlMan::Spirit_Easy),
    cxxlPreserve2(CC3D_Node_ClassID),
    m_Child_Nodes_Set(this,L"CC3D_Node.Child_Nodes"),
    m_WorldMatrix_cPtr(Matrix4x4_Arg)
  {
  }

  // Constructor
  CC3D_Node()
    :cxxlObject(CxxlMan::Spirit_Easy),
    cxxlPreserve2(CC3D_Node_ClassID),
    m_Child_Nodes_Set(this,L"CC3D_Node.Child_Nodes"),
    m_WorldMatrix_cPtr(new Matrix4x4(Matrix4x4::IdentityCreate()))
  {
  }

  virtual ~CC3D_Node()
  {

  }


  friend cxxlObject *New_CC3D_Node(void *p);
  friend cxxlPreserve2 *Regenera_CC3D_Node(const wchar_t *ClassID);

};



cxxlObject *New_CC3D_Node(void *p)
{
  return new CC3D_Node(*(const CSmart_Ptr<const Matrix4x4> *)p);
}

cxxlPreserve2 *Regenera_CC3D_Node(const wchar_t *ClassID)
{
  if(wcscmp(CC3D_Node_ClassID, ClassID) == 0)  // 只處理最終實作類別的識別碼就行了
    return new CC3D_Node();
  
  return NULL;
}

/*
extern "C" CXXL_DLLEXPORT
cxxlObject * cxxlCDECL CxxlMan_ObjectFactory(const wchar_t *ClassID, void *Arg,   ISpirit *spirit)
{
  if(wcscmp(IC3D_Node_ClassID, ClassID) == 0)  // 只處理介面就好
    return new CC3D_Node();

  return NULL;
}

extern "C" CXXL_DLLEXPORT
cxxlPreserve2 * cxxlCDECL CxxlMan_Preserve2Factory(const wchar_t *ClassID)
{
  if(wcscmp(CC3D_Node_ClassID, ClassID) == 0)  // 只處理最終實作類別的識別碼就行了
    return new CC3D_Node();
  
  return NULL;
}
*/